https://www.boost.org/doc/libs/1_55_0/doc/html/thread.html
thread
- 当创建一个thread对象后,线程就立刻开始执行。
- join()和timed_join()方法等待线程结束。
- join()一直阻塞等待,直到线程结束。
- timed_join()阻塞等待线程结束,或阻塞等待一定的时间段,然后不管线程是否结束都返回。
- detach()与线程执行体分离,线程执行体不受影响的继续执行直到运行结束。
- 可以使用bind()和function库。
- thread类的3个静态成员函数:
- yield() 指示当前线程放弃时间片,允许其他的线程运行。
- sleep() 让线程睡眠等待一小段时间。
- hardware_concurrency() 获得硬件系统可并行的线程数量,即CPU数量。
- thread::this_thread 子命名空间:
- get_id() 获得线程ID
- yield() 放弃时间片
- sleep() 睡眠等待
- at_thread_exit(func)函数,允许“登记”一个线程在结束的时候执行可调用物func,无论线程是否被中断。
- interrupt() 中断线程,允许正在执行的线程被中断,被中断的线程会抛出一个thread_interrupted异常。
创建线程4种方法以及分离或等待线程
在任何一个时间点上,线程是可结合的(joinable),或者是分离的(detached)。
void my_func()
{
std::cout << "detach-分离 或 join-等待 线程" << std::endl;
}
TEST(BoostThread, detachOrjoin)//简单线程,线程状态joinable、detached
{
boost::thread t(my_func);
boost::thread::yield();//当前线程放弃余下的时间片。
std::cout << t.joinable() << std::endl;
t.join();
boost::thread t1(my_func);
std::cout << t1.joinable() << std::endl;
t1.detach();
std::cout << t1.joinable() << std::endl;
}
//线程的创建需要传递给thread对象一个可调用物(函数或函数对象),它必须具
//有operator()以供线程执行。
boost::mutex io_mutex;
struct count
{
count(int id) : id(id) { }
void operator()()
{
for (int i = 0; i < 10; ++i)
{
boost::mutex::scoped_lock
lock(io_mutex);
std::cout << id << ": "
<< i << std::endl;
}
}
int id;
};
TEST(BoostThread, Typeobject)//复杂类型对象作为参数来创建线程
{
boost::thread thrd1(count(1));
boost::thread thrd2(count(2));
thrd1.join();
thrd2.join();
}
class HelloWorldStatic
{
public:
static void hello()
{
std::cout <<
"Hello world, I''m a thread!"
<< std::endl;
}
static void start()
{
boost::thread thrd(hello);
thrd.join();
}
};
TEST(BoostThread, InClassStatic)//类内部创建线程
{
HelloWorldStatic::start();//在这里start()和hello()方法都必须是static方法。
}
class HelloWorld
{
public:
void hello()
{
std::cout <<
"Hello world, I''m a thread!"
<< std::endl;
}
void start()
{
boost::function0< void> f = boost::bind(&HelloWorld::hello, this);
boost::thread thrd(f);
thrd.join();
}
};
TEST(BoostThread, InClass)//start()和hello()方法不是静态方法则采用此方法创建线程
{
HelloWorld hello;
hello.start();
}
class HelloWorldOut
{
public:
void hello(const std::string& str)
{
std::cout << str;
}
};
TEST(BoostThread, OutClass)
{
HelloWorldOut obj;
boost::thread thrd(boost::bind(&HelloWorldOut::hello, &obj, "Hello world, I''m a thread!" ) ) ;
thrd.join();
}
线程的参数传递
void func1(const int &id)
{
std::cout << "func1 id : " << id << std::endl;
}
struct MyThread
{
void operator()(const int &id)
{
std::cout << "MyThread id : " << id << std::endl;
}
void func1(const int &id)
{
std::cout << "MyThread::func1 id : " << id << std::endl;
}
};
TEST(BoostThread, Threadparameters)
{
//普通函数
boost::thread t1(func1, 11);
t1.join();
//函数对象
MyThread myThread;
boost::thread t2(myThread, 22);
t2.join();
//成员函数
boost::thread t3(&MyThread::func1, myThread, 33);
t3.join();
//临时对象
boost::thread t4(MyThread(), 44);
t4.join();
//对象引用
boost::thread t5(boost::ref(myThread), 55);
t5.join();
}
还可使用bing与ref
线程中断
禁用于回复中断:boost::this_thread::disable_interruption
与boost::this_thread::restore_interruption
void f()
{
// interruption enabled here
{
boost::this_thread::disable_interruption di;
// interruption disabled
{
boost::this_thread::disable_interruption di2;
// interruption still disabled
} // di2 destroyed, interruption state restored
// interruption still disabled
} // di destroyed, interruption state restored
// interruption now enabled
}
void g()
{
// interruption enabled here
{
boost::this_thread::disable_interruption di;
// interruption disabled
{
boost::this_thread::restore_interruption ri(di);
// interruption now enabled
} // ri destroyed, interruption disable again
} // di destroyed, interruption state restored
// interruption now enabled
}
函数检测当前线程是否允许中断:boost::this_thread::interruption_enabled()
函数检测当前线程是否被要求中断:boost::this_thread::interruption_requested()
类disable_interruption
是一个RAII类型的对象,它在构造时关闭线程的中断,析构时自动恢复线程的中断状态。在disable_interruption
的生命期内线程始终是不可中断的,除非使用了restore_interruption
对象。
restore_interruption
只能在disable_interruption
的作用域内使用,它在构造时临时打开线程的中断状态,在析构时又关闭中断状态。
thread库预定义了若干个线程的中断点:
boost::thread::join()
boost::thread::timed_join()
boost::thread::try_join_for(),
boost::thread::try_join_until(),
boost::condition_variable::wait()
boost::condition_variable::timed_wait()
boost::condition_variable::wait_for()
boost::condition_variable::wait_until()
boost::condition_variable_any::wait()
boost::condition_variable_any::timed_wait()
boost::condition_variable_any::wait_for()
boost::condition_variable_any::wait_until()
boost::thread::sleep()
boost::this_thread::sleep_for()
boost::this_thread::sleep_until()
boost::this_thread::interruption_point()
而最后一个位于子名字空间this_thread的interruption_point()则是一个特殊的中断点函数,它并不等待,只是起到一个标签的作用,表示线程执行到这个函数所在的语句就可以被中断。
thread_group线程组
thread库提供类thread_group用于管理一组线程,就像是一个线程池,它内部使用
std::list
void thread_group_Fun()
{
std::cout <<"当前线程ID:"<< boost::this_thread::get_id() << std::endl;
}
TEST(BoostThread, thread_group)
{
boost::thread_group grp;
boost::thread *p = new boost::thread(thread_group_Fun);
grp.add_thread(p);
std::cout << "remove_thread:" << p->get_id()<< std::endl;
grp.remove_thread(p);
grp.create_thread(thread_group_Fun);
grp.create_thread(thread_group_Fun);
grp.join_all();
}
##作用域线程 ##
boost::strict_scoped_thread<> t((boost::thread(F)));
boost::scoped_thread<> t((boost::thread(F)));
锁
Lock Guard
Class template lock_guard
Non Member Function make_lock_guard
Non Member Function make_lock_guard
boost::lock_guard 在其内部构造和析构函数分别自动调用 lock() 和 unlock() 。 访问共享资源是需要同步的,因为它显示地被两个方法调用。
使用 lock_guard 自动加锁、解锁。原理是 RAII,和智能指针类似。
RAII型的lock_guard类
直接使用mutex的lock()函数来锁定互斥量不够方便,且在发生异常退出作用域等情况下很可能忘记解锁。
故,thread库提供了RAII型lock_guard类,辅助:在构造时锁定互斥量,析构时自动解锁。
mutex类使用内部类型定义了两种lock_guard对象:
scoped_lock
scoped_try_lock
使用 unique_lock 自动加锁、解锁。
unique_lock 与 lock_guard 原理相同,但是提供了更多功能(比如可以结合条件变量使用)。
注意:mutex::scoped_lock 其实就是 unique_lock
Lock Types
Class template unique_lock
Class template shared_lock - C++14
Class template upgrade_lock - EXTENSION
Class template upgrade_to_unique_lock -- EXTENSION
Mutex-specific class scoped_try_lock -- DEPRECATED
boost::unique_lock 这个所谓的独占锁意味着一个互斥量同时只能被一个线程获取。 其他线程必须等待,直到互斥体再次被释放。 除了独占锁,还有非独占锁。 Boost.Thread里有个 boost::shared_lock 的类提供了非独占锁。
shared_lock是read lock。被锁后仍允许其他线程执行同样被shared_lock的代码。这是一般做读操作时的需要。
unique_lock是write lock。被锁后不允许其他线程执行被shared_lock或unique_lock的代码。在写操作时,一般用这个,可以同时限制unique_lock的写和share_lock的读。
boost::mutex::scoped_lock
boost::mutex io_mutex;
void foo( )
{
{
boost::mutex::scoped_lock lock( io_mutex ); /// 锁定
} /// 解锁
}
boost::lock_guard<>和boost::unique_lock<>的区别
boost::mutex m;
void foo( )
{
boost::lock_guard<boost::mutex> lk( m );
process( data );
};
//lock_guard只能像上面这样使用,而unique_lock允许设置超时,推迟锁定lock以及在对象销毁之前unlock。
{
boost::unique_lock<boost::mutex> lk( m );
process( data );
lk.unlock( );
// do other thing
};
设置锁超时
boost::unique_lock<boost::timed_mutex> lk( m, std::chrono::milliseconds(3) ); // 超时3秒
if( lk ) process( data );
Other Lock Types - EXTENSION
Strict Locks
Locking pointers
Externally Locked
Class template shared_lock_guard
Class template reverse_lock
互斥类型
独占式互斥量:
Class mutex
Typedef try_mutex
Class timed_mutex
递归式互斥量:
Class recursive_mutex
Typedef recursive_try_mutex
Class recursive_timed_mutex
boost::recursive_mutex提供一个递归式的互斥量。对于一个实例最多允许一个线程拥有其锁定,如果一个线程已经锁定一个boost::recursive_mutex实例,那么这个线程可以多次锁定这个实例。
共享式互斥量:
Class shared_mutex -- C++14
Class upgrade_mutex -- EXTENSION
其他:
Class null_mutex -- EXTENSION
读写锁
typedef boost::shared_lock<boost::shared_mutex> readLock;
typedef boost::unique_lock<boost::shared_mutex> writeLock;
boost::shared_mutex rwmutex;
std::vector<int> random_numbers;
void readOnly()
{
for (int i = 0; i < 3; ++i)
{
wait(1);
readLock rdlock(rwmutex);
std::cout << random_numbers.back() << std::endl;
}
}
void writeOnly()
{
std::srand(static_cast<unsigned int>(std::time(0)));
for (int i = 0; i < 3; ++i)
{
writeLock wtlock(rwmutex);
random_numbers.push_back(std::rand());
wait(1);
}
}
int sum = 0;
void count()
{
for (int i = 0; i < 3; ++i)
{
wait(1);
readLock rdlock(rwmutex);
sum += random_numbers.back();
}
}
TEST(BoostThread, readwrite)//读写锁
{
boost::thread t1(writeOnly);
boost::thread t2(readOnly);
boost::thread t3(count);
t1.join();
t2.join();
t3.join();
std::cout << "Sum: " << sum << std::endl;
}
shared_mutex 比一般的 mutex 多了函数 lock_shared() / unlock_shared(),允许多个(读者)线程同时加锁、解锁,而 shared_lock 则相当于共享版的 lock_guard。
对 shared_mutex 使用 lock_guard 或 unique_lock 就达到了写者独占的目的。
Condition Variables条件变量
从一个线程中给另一个线程发送通知
条件变量是thread库提供的另一种用于等待的同步机制,可以实现线程间的通信,它必须和互斥量配合使用,等待另一个线程中某个事件的发送(满足某个条件),然后线程才能继续执行。
thread库提供两种条件变量对象:
condition_variable
condition_variable_any (常用,能够适应更广泛的互斥量类型)
条件变量的使用方法很简单:
拥有条件变量的线程先锁定互斥量,然后循环检查某个条件,如果条件不满足,那么
就调用变量的成员函数wait()等待直至条件满足。其他线程处理条件变更要求的条件,
当条件满足时调用它的成员函数notify_one()或notify_all(),以通知一个或者所
有正在等待条件变更的线程停止等待继续执行。
其他用法
条件变量的wait()函数有一个有用的重载形式:wiat(lock_type& lock, predicate_type
predicate),它比普通的形式多接受一个谓词函数(或函数对象),当谓词predicate不
满足时持续等待。
使用这个重载形式或以写出更简洁清晰的代码,通常需要配合bind来简化谓词函数的
编写。
例如,buffer类的两个条件变量的等待可以改写成:
cond_put.wait(mu, !bind(&buffer::is_full, this));
cond_get.wait(mu, !bind(&buffer::is_empty, this));
https://segmentfault.com/a/1190000006679917
条件变量读写
boost::condition_variable_any cond;
boost::mutex rwmutexCV;
std::vector<int> random_numbersCV;
void print()
{
std::size_t next_size = 1;
for (int i = 0; i < 3; ++i)
{
boost::unique_lock<boost::mutex> lock(rwmutexCV);
while (random_numbersCV.size() != next_size)
cond.wait(rwmutexCV);
std::cout << random_numbersCV.back() << std::endl;
++next_size;
cond.notify_all();
}
}
void fill()
{
std::srand(static_cast<unsigned int>(std::time(0)));
for (int i = 0; i < 3; ++i)
{
boost::unique_lock<boost::mutex> lock(rwmutexCV);
random_numbersCV.push_back(std::rand());
cond.notify_all();
cond.wait(rwmutexCV);
}
}
TEST(BoostThread, ConditionVariables)//条件变量
{
boost::thread t1(fill);
boost::thread t2(print);
t1.join();
t2.join();
}
生产者-消费者模式的后进先出型(std::stack)缓冲区
class Buffer
{
public:
//构造函数
Buffer(size_t n) :un_read(0), capacity(n) {}
//写入数据x
void put(int x) {
//局部域
{
boost::mutex::scoped_lock lock(mu); //锁定互斥量
while (is_full()) {
cond_put.wait(mu); //条件变量等待
}
stk.push(x); //写入数据
++un_read;
} //解锁互斥量
cond_get.notify_one(); //通知可以读取数据
}
//读取数据
void get(int *x) {
{
boost::mutex::scoped_lock lock(mu);
while (is_empty()) {
cond_get.wait(mu);
}
*x = stk.top();
stk.pop();
--un_read;
}
cond_put.notify_one();
}
private:
//判断缓冲区是否满
bool is_full() {
return un_read == capacity;
}
//判断缓冲区是否为空
bool is_empty() {
return un_read == 0;
}
private:
boost::mutex mu; //互斥量,配合条件变量使用
boost::condition_variable_any cond_put; //写入条件变量
boost::condition_variable_any cond_get; //读取条件变量
std::stack<int> stk; //缓冲区对象
int un_read;
int capacity;
};
Buffer buf(5); //定义一个缓冲区对象
boost::mutex io_mu_; //定义一个输出互斥量
//生产者,n个
void producer(int n)
{
for (int i = 0; i < n; i++) {
//输出信息
{
boost::mutex::scoped_lock lock(io_mu_);
std::cout << "put " << i << " to buffer" << std::endl;
}
buf.put(i); //写入数据
}
}
//消费者
void consumer(int n)
{
int result(0);
for (int i = 0; i < n; i++) {
{
buf.get(&result); //读取数据
boost::mutex::scoped_lock lock(io_mu_);
std::cout << "get " << result << " from buffer" << std::endl;
}
}
}
TEST(BoostThread, producer_consumer_test)
{
boost::thread t_producer(producer, 20);
boost::thread t_consumer1(consumer, 10);
boost::thread t_consumer2(consumer, 10);
t_producer.join();
t_consumer1.join();
t_consumer2.join();
}
https://segmentfault.com/a/1190000006703543
#include <iostream>
#include <vector>
#include <boost/utility.hpp>
#include <boost/thread/condition_variable.hpp>
#include <boost/thread/thread.hpp>
class BoundedBuffer : private boost::noncopyable {
public:
BoundedBuffer(size_t size)
: begin_(0), end_(0), buffered_(0), circular_buffer_(size) {
}
void Produce(int n) {
boost::unique_lock<boost::mutex> lock(mutex_);
// 等待缓冲不为满。
not_full_cv_.wait(lock, [=] { return buffered_ < circular_buffer_.size(); });
// 插入新的元素,更新下标。
circular_buffer_[end_] = n;
end_ = (end_ + 1) % circular_buffer_.size();
++buffered_;
// 通知前,手动解锁。
lock.unlock();
// 通知消费者。
not_empty_cv_.notify_one();
}
int Consume() {
boost::unique_lock<boost::mutex> lock(mutex_);
// 等待缓冲不为空。
not_empty_cv_.wait(lock, [=] { return buffered_ > 0; });
// 移除一个元素。
int n = circular_buffer_[begin_];
begin_ = (begin_ + 1) % circular_buffer_.size();
--buffered_;
// 通知前,手动解锁。
lock.unlock();
// 通知生产者。
not_full_cv_.notify_one();
return n;
}
private:
size_t begin_;
size_t end_;
size_t buffered_;
std::vector<int> circular_buffer_;
boost::condition_variable not_full_cv_;
boost::condition_variable not_empty_cv_;
boost::mutex mutex_;
};
BoundedBuffer g_buffer(2);
boost::mutex g_io_mutex;
void Producer() {
int n = 0;
while (n < 100000) {
g_buffer.Produce(n);
if ((n % 10000) == 0) {
boost::unique_lock<boost::mutex> lock(g_io_mutex);
std::cout << "Produce: " << n << std::endl;
}
++n;
}
g_buffer.Produce(-1);
}
void Consumer() {
boost::thread::id thread_id = boost::this_thread::get_id();
int n;
do {
n = g_buffer.Consume();
if ((n % 10000) == 0) {
boost::unique_lock<boost::mutex> lock(g_io_mutex);
std::cout << "Consume: " << n << " (" << thread_id << ")" << std::endl;
}
} while (n != -1); // -1 表示缓冲已达末尾。
// 往缓冲里再放一个 -1,这样其他消费者才能结束。
g_buffer.Produce(-1);
}
int main() {
boost::thread_group threads;
threads.create_thread(&Producer);
threads.create_thread(&Consumer);
threads.create_thread(&Consumer);
threads.create_thread(&Consumer);
threads.join_all();
return 0;
}
线程池
https://segmentfault.com/a/1190000006691692
也可使用ATL的ThreadPool或http://threadpool.sourceforge.net/
#include <iostream>
#include <boost/thread/thread.hpp>
#include <boost/bind.hpp>
#include <boost/asio.hpp>
class ThreadPool {
public:
explicit ThreadPool(size_t size) : work_(io_service_) {
for (size_t i = 0; i < size; ++i) {
workers_.create_thread(
boost::bind(&boost::asio::io_service::run, &io_service_));
}
}
~ThreadPool() {
io_service_.stop();
workers_.join_all();
}
// Add new work item to the pool.
template<class F>
void Enqueue(F f) {
io_service_.post(f);
}
private:
boost::thread_group workers_;
boost::asio::io_service io_service_;
boost::asio::io_service::work work_;
};
成员变量 io_service::work 的作用是,让 asio::io_service 即使在没有异步任务可执行时也保持运行(即 io_service::run 不返回)。
int main() {
// Create a thread pool of 4 worker threads.
ThreadPool pool(4);
// Queue a bunch of work items.
for (int i = 0; i < 8; ++i) {
pool.Enqueue([i] {
std::cout << "hello " << i << std::endl;
boost::this_thread::sleep(boost::posix_time::seconds(1));
std::cout << "world " << i << std::endl;
});
}
return 0;
}
线程局部存储
Boost线程库提供了智能指针boost::thread_specific_ptr来访问本地存储线程。每一个线程第一次使用这个智能指针的实例时,它的初值是NULL,所以必须要先检查这个它的只是否为空,并且为它赋值。Boost线程库保证本地存储线程中保存的数据会在线程结束后被清除。
void init_number_generator()
{
static boost::thread_specific_ptr<bool> tls;
if (!tls.get())
tls.reset(new bool(false));
if (!*tls)
{
*tls = true;
std::srand(static_cast<unsigned int>(std::time(0)));
}
}
boost::mutex mutex;
void random_number_generator()
{
init_number_generator();
int i = std::rand();
boost::lock_guard<boost::mutex> lock(mutex);
std::cout << i << std::endl;
}
TEST(BoostThread, thread_specific_ptr)//线程局部存储
{
boost::thread t[3];
for (int i = 0; i < 3; ++i)
t[i] = boost::thread(random_number_generator);
for (int i = 0; i < 3; ++i)
t[i].join();
}
只初始化一次共享资源
std::call_once
准确执行一次可调用 (Callable) 对象 f ,即使同时从多个线程调用。
#include <iostream>
#include <thread>
#include <mutex>
std::once_flag flag1, flag2;
void simple_do_once()
{
std::call_once(flag1, [](){ std::cout << "Simple example: called once\n"; });
}
void may_throw_function(bool do_throw)
{
if (do_throw) {
std::cout << "throw: call_once will retry\n"; // 这会出现多于一次
throw std::exception();
}
std::cout << "Didn't throw, call_once will not attempt again\n"; // 保证一次
}
void do_once(bool do_throw)
{
try {
std::call_once(flag2, may_throw_function, do_throw);
}
catch (...) {
}
}
int main()
{
std::thread st1(simple_do_once);
std::thread st2(simple_do_once);
std::thread st3(simple_do_once);
std::thread st4(simple_do_once);
st1.join();
st2.join();
st3.join();
st4.join();
std::thread t1(do_once, true);
std::thread t2(do_once, true);
std::thread t3(do_once, false);
std::thread t4(do_once, true);
t1.join();
t2.join();
t3.join();
t4.join();
}
boost::call_once
#include <iostream>
#include <boost/thread/thread.hpp>
#include <boost/thread/once.hpp>
// Some sort of connection class that should only be initialized once
struct Conn {
static void init( ) {++i_;}
static boost::once_flag init_;
static int i_;
// ...
};
int Conn::i_ = 0;
boost::once_flag Conn::init_ = BOOST_ONCE_INIT;
void worker( ) {
boost::call_once(Conn::init, Conn::init_);
// Do the real work...
}
Conn c; // You probably don't want to use a global, so see the
// next Recipe
int main( ) {
boost::thread_group grp;
for (int i = 0; i < 100; ++i)
grp.create_thread(worker);
grp.join_all( );
std::cout << c.i_ << '\n';// c.i_ = 1
}
一个共享资源不得不在某个地方被初始化,并且你希望第一次使用这个资源的线程来完成初始化工作。一个once_flag类型和call_once函数能够保证多个线程不会重复的初始化同一个对象。首先,必须使用BOOST_ONCE_INIT宏来初始化这个once_flag对象。boost::onceflag Conn::init = BOOST_ONCE_INIT; 之后调用call_once函数,boost::callonce(Conn::init, Conn::init); 第一个形参是希望被执行一次的初始化函数的地址。
原子操作
boost::atomic<>
Futures
很多情况下线程不仅仅要执行一些工作,它还可能要返回一些计算结果。
thread库使用future范式提供了一种异步操作线程返回值的方法,
future使用packaged_task和promise两个模板类来包装异步调用,用unique_future
和shared_future来获取异步调用结果(即future值)。
package_task和unique_future
packaged_task用来存储packaged_task异步计算得到的future值,它只能持有结果的
唯一的一个引用。成员函数wait()和timed_wait()的行为类似thread.join(),可以
阻塞等待packaged_task的执行,直至获得future值。成员函数is_ready()、has_value()
和has_exception()分别用来测试unique_future是否可用。
下面代码示范了future特性的用法,使用packaged_task和unique_future:
int fab(int n)
{
if (n == 0 || n == 1)
{
return 1;
}
return fab(n - 1) + fab(n - 2);
}
int main()
{
// 声明packaged_task对象,用模板参数指明返回值类型
// packaged_task只接受无参函数,因此需要使用bind
packaged_task<int> pt(bind(fab, 10));
// 声明unique_future对象,接受packaged_task的future值
// 同样要用模板参数指明返回值类型
unique_future<int> uf = pt.get_future();
// 启动线程计算,必须使用boost::move()来转移package_task对象
// 因为packaged_task是不可拷贝的
thread(boost::move(pt));
uf.wait(); // unique_future等待计算结果
assert(uf.is_ready() && uf.has_value());
cout << uf.get(); // 输出计算结果99
}
使用多个future对象
为了支持多个future对象的使用,future还提供wait_for_any()和wiat_for_all()两个
自由函数,它们可以阻塞等待多个future对象,直到任意一个或者所有future对象都
可以(is_ready())。这两个函数有多个重载形式,可以接受一对表示future容器区间
的迭代器或者最多5个future对象。
promise
promise也用于处理异步调用返回值,但它不同于packaged_task,不能包装一个函数,
而是包装一个值,这个值可以作为函数的输出参数,适用于从函数参数返回值的函数。
promise的用法与packaged_task类似,在线程中用set_value()设置要返回的值,用
成员函数get_future()获得future值赋给future对象。
int calculate_the_answer_to_life_the_universe_and_everything()
{
return 42;
}
void invoke_lazy_task(boost::packaged_task<int>& task)
{
try
{
task();
}
catch (boost::task_already_started&)
{
}
}
//shared_future与unique_future
TEST(BoostThread, BoostFuture)
{
{
boost::packaged_task<int> pt(calculate_the_answer_to_life_the_universe_and_everything);
boost::unique_future<int> fi = pt.get_future();
boost::thread task(boost::move(pt)); // launch task on a thread
fi.wait(); // wait for it to finish
ASSERT_TRUE(fi.is_ready());
ASSERT_TRUE(fi.has_value());
ASSERT_TRUE(!fi.has_exception());
ASSERT_TRUE(fi.get_state() == boost::future_state::ready);
ASSERT_TRUE(fi.get() == 42);
}
{
boost::promise<int> pi;
boost::unique_future<int> fi;
fi = pi.get_future();
pi.set_value(42);
ASSERT_TRUE(fi.is_ready());
ASSERT_TRUE(fi.has_value());
ASSERT_TRUE(!fi.has_exception());
ASSERT_TRUE(fi.get_state() == boost::future_state::ready);
ASSERT_TRUE(fi.get() == 42);
}
{
boost::packaged_task<int> task(calculate_the_answer_to_life_the_universe_and_everything);
task.set_wait_callback(invoke_lazy_task);
boost::unique_future<int> f(task.get_future());
ASSERT_TRUE(f.get() == 42);
}
}
参考
- https://www.cnblogs.com/renyuan/p/6613638.html
- https://blog.csdn.net/lp310018931/article/details/50596469
- https://www.cnblogs.com/lidabo/p/3785176.html
- https://blog.csdn.net/yvhqbat/article/details/51922153
- https://blog.csdn.net/liujiayu2/article/details/50587064
- https://blog.csdn.net/u012592062/article/details/80467118
- C++ 并发编程指南